#include "gtest/gtest.h"
#include "Object.h"

USING_NS_B2D

class ClassA : public Object
{
	B2D_OBJECT
};
class ClassB : public ClassA
{
	B2D_OBJECT
};
B2D_OBJECT_IMPL(ClassA,Object)
B2D_OBJECT_IMPL(ClassB,ClassA)

TEST(test_object, type_derives_from)
{
	ObjectType baseType;
	ObjectType classAType = ClassA::Type;
	ObjectType classBType = ClassB::Type;

	ClassB classB;

	bool classADerivesFromBase = classAType.derivesFromType(baseType);
	bool classBDerivesFromBase = classBType.derivesFromType(baseType);
	bool classBDerivesFromA = classBType.derivesFromType(classAType);
	bool classADerivesFromB = classAType.derivesFromType(classBType);
	bool instanceBDerivesFromBase = classB.derivesFromType(baseType);

	EXPECT_EQ(true, classADerivesFromBase);
	EXPECT_EQ(true, classBDerivesFromBase);
	EXPECT_EQ(true, classBDerivesFromA);
	EXPECT_EQ(false, classADerivesFromB);
	EXPECT_EQ(true, instanceBDerivesFromBase);
}

TEST(test_object, types_are_equal)
{
	ObjectType classAType = ClassA::Type;
	ObjectType classBType = ClassB::Type;
	ObjectType classAType2 = classAType;

	ClassA classA;

	bool classAEqualsA = classAType.isOfType(classAType);
	bool classAEqualsA2 = classAType.isOfType(classAType2);
	bool classBEqualsA = classBType.isOfType(classAType);
	bool classAEqualsB = classAType.isOfType(classBType);
	bool instanceAEqualsA = classA.isOfType(classAType);

	EXPECT_EQ(true, classAEqualsA);
	EXPECT_EQ(true, classAEqualsA2);
	EXPECT_EQ(false, classBEqualsA);
	EXPECT_EQ(false, classAEqualsB);
	EXPECT_EQ(true, instanceAEqualsA);
}

TEST(test_object, object_dynamic_cast)
{
	ClassA _a;
	ClassB _b;

	ClassB* b_bptr = &_b;
	ClassA* a_aptr = &_a;
	ClassA* b_aptr = &_b;
	Object* a_optr = &_a;
	Object* n_optr = nullptr;

	bool b_bptr_to_a = object_dynamic_cast<ClassA>(b_bptr);
	bool a_aptr_to_b = object_dynamic_cast<ClassB>(a_aptr);
	bool b_aptr_to_b = object_dynamic_cast<ClassB>(b_aptr);
	bool a_optr_to_a = object_dynamic_cast<ClassA>(a_optr);
	bool n_optr_to_a = object_dynamic_cast<ClassA>(n_optr);

	EXPECT_EQ(true, b_bptr_to_a);
	EXPECT_EQ(false, a_aptr_to_b);
	EXPECT_EQ(true, b_aptr_to_b);
	EXPECT_EQ(true, a_optr_to_a);
	EXPECT_EQ(false, n_optr_to_a);
}

TEST(test_object, object_type_equality_operators)
{
	ClassA a0;
	ClassA a1;
	ClassB b0;

	bool a0_eq_a1 = (a0.Type == a1.Type);
	bool a0_eq_b0 = (a0.Type == b0.Type);
	bool a0_neq_a1 = (a0.Type != a1.Type);
	bool a1_neq_b0 = (a1.Type != b0.Type);

	EXPECT_EQ(true, a0_eq_a1);
	EXPECT_EQ(false, a0_eq_b0);
	EXPECT_EQ(false, a0_neq_a1);
	EXPECT_EQ(true, a1_neq_b0);
}